package com.ruoyi.business.sundry.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.business.base.JoBaseServiceImpl;
import com.ruoyi.business.base.PageParam;
import com.ruoyi.business.goods.domain.JbCommodity;
import com.ruoyi.business.goods.domain.vo.JbCommodityVo;
import com.ruoyi.business.goods.service.JbCommodityService;
import com.ruoyi.business.sundry.domain.JbProductMaterialMapping;
import com.ruoyi.business.sundry.domain.JbProductRecipe;
import com.ruoyi.business.sundry.domain.JbProductRecipeHistory;
import com.ruoyi.business.sundry.domain.JbRawMaterialPrice;
import com.ruoyi.business.sundry.domain.vo.JbProductMaterialMappingVo;
import com.ruoyi.business.sundry.domain.vo.JbProductRecipeMappingVo;
import com.ruoyi.business.sundry.domain.vo.JbProductRecipeVo;
import com.ruoyi.business.sundry.mapper.JbProductRecipeMapper;
import com.ruoyi.business.sundry.service.JbProductMaterialMappingService;
import com.ruoyi.business.sundry.service.JbProductRecipeHistoryService;
import com.ruoyi.business.sundry.service.JbProductRecipeService;
import com.ruoyi.business.sundry.service.JbRawMaterialPriceService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.thirdparty.chanjet.service.impl.ThirdpartyCommodityInventoryServiceImpl;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * 商品配方Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-11
 */
@Log4j2
@Service
public class JbProductRecipeServiceImpl
        extends JoBaseServiceImpl<JbProductRecipeMapper, JbProductRecipe>
        implements JbProductRecipeService
{
    @Autowired
    private JbRawMaterialPriceService jbRawMaterialPriceService;
    @Autowired
    private JbProductMaterialMappingService jbProductMaterialMappingService;
    @Autowired
    private JbProductRecipeHistoryService jbProductRecipeHistoryService;
    @Autowired
    private ThirdpartyCommodityInventoryServiceImpl thirdpartyCommodityInventoryService;
    @Autowired
    private JbCommodityService commodityService;

    @Override
    public IPage<JbProductRecipeVo> pageList(PageParam pageParam, JbProductRecipe jbProductRecipe)
    {
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jpr.id,
                	jpr.commodity_id,
                	jc.commodity_name AS productName,
                	jpr.pesticide_registration_number,
                	jpr.inventory_cost as inventoryCost,
                	jpr.real_time_cost,
                	jpr.update_time,
                	jpr.update_by,
                	su.user_name AS updateName\s
                FROM
                	jb_product_recipe jpr
                	LEFT JOIN jb_commodity jc ON jc.id = jpr.commodity_id
                	LEFT JOIN sys_user su ON jpr.update_by = su.user_id\s
                WHERE
                	jpr.del_flag = 0\s
                	AND jc.del_flag = 0
                """);
        sql.add(joSqlUtil.sqlIf(" and (INSTR(jc.commodity_name,'#{keyword}')>0" +
                                " or INSTR(jpr.pesticide_registration_number,'#{keyword}')>0 )"
                , pageParam.getKeyword()));
        sql.add(" order by jpr.id desc ");
        String s = joSqlUtil.sqlJson(sql.toString(), pageParam);
        IPage<JbProductRecipeVo> iPage = joSqlUtil.jsonToEntity(baseMapper.pageJson(pageParam.b(), s),
                JbProductRecipeVo.class);
        return iPage;
    }

    @Override
    public Boolean synchronizationGoods()
    {
        Integer count = baseMapper.addFSql("""
                INSERT INTO jb_product_recipe ( commodity_id, product_name, product_specification, product_specification_unit, pesticide_registration_number ) SELECT
                jc.id,
                jc.commodity_name,
                jc.unit_content,
                jc.content_unit,
                jp.pesticide_registration_number
                FROM
                	jb_commodity jc
                	LEFT JOIN jb_product jp ON jc.product_id = jp.id
                WHERE
                	jc.del_flag = 0
                	AND jp.del_flag = 0
                	AND jc.id NOT IN ( SELECT commodity_id FROM jb_product_recipe )
                """);
        log.info("[{}]:{}", "商品配方同步商品信息(synchronizationGoods)", count);
        return true;
    }

    @Override
    public JbProductRecipeVo getDetails(Long id)
    {
        JbProductRecipe byId = getById(id);
        //获取商品名称
        if (StringUtils.isNotBlank(byId.getCommodityId()))
        {
            JbCommodity commodity = commodityService.getById(byId.getCommodityId());
            byId.setProductName(ObjectUtils.isNotEmpty(commodity) ? commodity.getCommodityName() : StringUtils.EMPTY);
        }
        //获取库存成本
        // JbCommodity commodity = commodityService.getById(byId.getCommodityId());
        // if (ObjectUtils.isNotEmpty(commodity) && StringUtils.isNotBlank(commodity.getCommodityCode()))
        // {
        //     ThirdpartyCommodityInventory one =
        //             thirdpartyCommodityInventoryService.getOne(Wrappers.lambdaQuery(ThirdpartyCommodityInventory
        //             .class)
        //                             .eq(ThirdpartyCommodityInventory::getCommodityCode, commodity.getCommodityCode())
        //                     , false);
        //     byId.setInventoryCost(Convert.toBigDecimal(ObjectUtils.isNotEmpty(one)
        //             ? one.getInventory() : 0, BigDecimal.ZERO));
        // }
        //获取配方的原料
        JbProductRecipeVo bean = BeanUtil.toBean(byId, JbProductRecipeVo.class);
        StringJoiner sql = new StringJoiner("").add("""
                SELECT
                	rmp.material_name,
                	rmp.material_id,
                	pmm.material_percentage,
                    pmm.mater_id,
                	rmp.latest_price\s
                FROM
                	jb_product_material_mapping pmm
                	INNER JOIN jb_raw_material_price rmp ON pmm.mater_id = rmp.id\s
                WHERE
                	pmm.del_flag = 0\s
                	AND rmp.del_flag = 0\s
                
                """);
        sql.add(String.format(" AND pmm.recipe_id = %s ", id));
        List<JbProductMaterialMappingVo> jbProductMaterialMappingVos =
                joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()), JbProductMaterialMappingVo.class);
        bean.setProductMaterialMappings(jbProductMaterialMappingVos);
        return bean;
    }

    @Override
    @Transactional
    public Boolean editInfo(JbProductRecipeVo jbProductRecipeVo)
    {
        JbProductRecipe byId = getById(jbProductRecipeVo.getId());
        setHistory(byId);
        JbProductRecipe jbProductRecipe = BeanUtil.toBean(jbProductRecipeVo, JbProductRecipe.class);
        jbProductRecipe.setRealTimeCost(setRealTimeCost(jbProductRecipeVo));
        return updateById(jbProductRecipe);
    }

    @Override
    @Transactional
    public Boolean addInfo(JbProductRecipeVo jbProductRecipeVo)
    {
        JbProductRecipe jbProductRecipe = BeanUtil.toBean(jbProductRecipeVo, JbProductRecipe.class);
        save(jbProductRecipe);
        jbProductRecipeVo.setId(jbProductRecipe.getId());
        jbProductRecipe.setRealTimeCost(setRealTimeCost(jbProductRecipeVo));
        return updateById(jbProductRecipe);
    }

    @Override
    public Boolean updateRealTimeCost(Map<Long, BigDecimal> materialList)
    {
        String ids = materialList.entrySet().stream().map(a -> a.getKey().toString()).collect(Collectors.joining(","));
        // 获取那些材料，被分配使用，更新配方实时成本，增加配方历史记录
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	rmpt.recipe_id,rmpt.mater_id,rmpt.material_percentage,
                	rmpt.latest_price,
                	rmpt.id as mappingId,
                	pr.*
                FROM
                	jb_product_material_mapping pmm
                	INNER JOIN jb_product_material_mapping rmpt ON rmpt.recipe_id = pmm.recipe_id
                	INNER JOIN jb_product_recipe pr on rmpt.recipe_id=pr.id
                WHERE
                	pmm.del_flag = 0\s
                	AND rmpt.del_flag = 0\s
                
                """);
        sql.add(String.format(" AND rmpt.mater_id in (%s)", String.join(",", ids)));
        List<JbProductRecipeMappingVo> mapList = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbProductRecipeMappingVo.class);
        if (ObjectUtils.isNotEmpty(mapList))
        {
            Map<Long, List<JbProductRecipeMappingVo>> recipeMap =
                    mapList.stream().collect(Collectors.groupingBy(JbProductRecipeMappingVo::getId));
            for (Map.Entry<Long, List<JbProductRecipeMappingVo>> entry : recipeMap.entrySet())
            {
                List<JbProductRecipeMappingVo> value = entry.getValue();
                if (ObjectUtils.isEmpty(value))
                {
                    continue;
                }
                // 添加一条历史记录
                JbProductRecipe productRecipe = BeanUtil.toBean(value.get(0), JbProductRecipe.class);
                setHistory(productRecipe);
                BigDecimal realTimeCost = BigDecimal.ZERO;
                List<JbProductMaterialMapping> mappingList = Lists.newArrayList();
                // 计算最新的实时成本
                for (JbProductRecipeMappingVo vo : value)
                {
                    // 最新价格
                    BigDecimal bigDecimal = vo.getLatestPrice();
                    if (ObjectUtils.isNotEmpty(materialList.get(vo.getMaterId())))
                    {
                        bigDecimal = materialList.get(vo.getMaterId());
                        JbProductMaterialMapping materialMapping = new JbProductMaterialMapping();
                        materialMapping.setId(vo.getMappingId());
                        materialMapping.setLatestPrice(bigDecimal);
                        mappingList.add(materialMapping);
                    }
                    if (ObjectUtils.isNotEmpty(vo.getMaterialPercentage()))
                    {
                        BigDecimal multiply = vo.getMaterialPercentage().divide(new BigDecimal(100), 2,
                                BigDecimal.ROUND_UP).multiply(bigDecimal);
                        realTimeCost = realTimeCost.add(multiply);
                    }
                }
                // 更新最新的实时成本
                productRecipe = new JbProductRecipe();
                productRecipe.setId(entry.getKey());
                productRecipe.setRealTimeCost(realTimeCost);
                updateById(productRecipe);
                // 更新配方和原料最新的成本数据
                if (ObjectUtils.isNotEmpty(mappingList))
                {
                    jbProductMaterialMappingService.updateBatchById(mappingList);
                }
            }
        }
        return null;
    }

    /**
     * 添加历史
     *
     * @param byId
     */
    private void setHistory(JbProductRecipe byId)
    {
        // 存储历史
        JbProductRecipeHistory history = BeanUtil.toBean(byId, JbProductRecipeHistory.class);
        history.setId(null);
        history.setProductRecipeId(byId.getId());
        // 获取商品名称和实时库存
        // JbCommodityVo commodityInventory = getCommodityInventory(byId.getId());
        // if (ObjectUtils.isNotEmpty(commodityInventory))
        // {
        //     history.setProductName(commodityInventory.getCommodityName());
        //     history.setInventoryCost(commodityInventory.getInventory());
        // }
        history.setProductName(byId.getProductName());
        history.setInventoryCost(byId.getInventoryCost());
        // 存储配置和原料到历史
        List<JbProductMaterialMapping> mappingList =
                jbProductMaterialMappingService.list(Wrappers.lambdaQuery(JbProductMaterialMapping.class)
                        .eq(JbProductMaterialMapping::getRecipeId, byId.getId()));
        if (ObjectUtils.isNotEmpty(mappingList))
        {
            String jsonString = JSONArray.toJSONString(mappingList);
            history.setMaterialContent(jsonString);
        }
        jbProductRecipeHistoryService.save(history);
    }

    private JbCommodityVo getCommodityInventory(Long id)
    {
        JbCommodityVo vo = new JbCommodityVo();
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jc.id,
                	jc.commodity_name,
                	( SELECT tci.inventory FROM thirdparty_commodity_inventory tci WHERE jc.commodity_code = tci.commodity_code LIMIT 1 ) AS inventory\s
                FROM
                	jb_commodity jc\s
                WHERE
                	jc.del_flag =0
                """);
        sql.add(String.format(" and jc.id=%s", id));
        List<JbCommodityVo> listHistory = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbCommodityVo.class);
        if (ObjectUtils.isNotEmpty(listHistory))
        {
            vo = listHistory.get(0);
        }
        return vo;
    }

    /**
     * 计算实时价格，和查询配方和原料关系数据
     *
     * @param jbProductRecipeVo
     * @return
     */
    private BigDecimal setRealTimeCost(JbProductRecipeVo jbProductRecipeVo)
    {
        BigDecimal realTimeCost = BigDecimal.ZERO;
        List<JbProductMaterialMappingVo> productMaterialMappings = jbProductRecipeVo.getProductMaterialMappings();
        if (ObjectUtils.isNotEmpty(productMaterialMappings))
        {
            // 删除以前的
            jbProductMaterialMappingService.remove(Wrappers.lambdaQuery(JbProductMaterialMapping.class)
                    .eq(JbProductMaterialMapping::getRecipeId, jbProductRecipeVo.getId()));
            // 获取最新的原料价格
            List<Long> mIds =
                    productMaterialMappings.stream().map(JbProductMaterialMappingVo::getMaterId).collect(Collectors.toList());
            List<JbRawMaterialPrice> prices = jbRawMaterialPriceService.listByIds(mIds);

            //原材料价格有空值， 无法完成计算，抛出异常到前台
            Map<Long, BigDecimal> collect = new HashMap<>();
            for (JbRawMaterialPrice price : prices)
            {
                if (ObjectUtils.isEmpty(price.getLatestPrice()))
                {
                    throw new ServiceException(
                            com.ruoyi.common.utils.StringUtils.format(
                                    "原材料 {} 最新价格为空，无法计算",
                                    price.getMaterialName()
                            )
                    );
                }
                collect.put(price.getId(), price.getLatestPrice());
            }

            List<JbProductMaterialMapping> materialMappings = Lists.newArrayList();
            // 计算所有原来一起的成本
            for (JbProductMaterialMappingVo vo : productMaterialMappings)
            {
                vo.setRecipeId(jbProductRecipeVo.getId());
                // 最新价格
                BigDecimal bigDecimal = collect.get(vo.getMaterId());
                if (ObjectUtils.isNotEmpty(vo.getMaterialPercentage()) && ObjectUtils.isNotEmpty(bigDecimal)
                    && vo.getMaterialPercentage().compareTo(BigDecimal.ZERO) > 0)
                {
                    BigDecimal multiply = vo.getMaterialPercentage().divide(new BigDecimal(100), 2,
                            BigDecimal.ROUND_UP).multiply(bigDecimal);
                    realTimeCost = realTimeCost.add(multiply);
                }
                JbProductMaterialMapping materialMapping = BeanUtil.toBean(vo, JbProductMaterialMapping.class);
                materialMapping.setRecipeId(jbProductRecipeVo.getId());
                materialMapping.setLatestPrice(bigDecimal);
                materialMappings.add(materialMapping);
            }
            // 插入最新的配方和原料关系
            jbProductMaterialMappingService.saveBatch(materialMappings);
        }
        return realTimeCost;
    }
}
